home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pctchnqs / 1991 / number2 / comio.pas < prev    next >
Pascal/Delphi Source File  |  1990-10-04  |  4KB  |  169 lines

  1. {$R-,S-}
  2. unit ComIO;
  3. { Low level serial interface routines using inline assembler
  4.   for interrupt service }
  5.  
  6. Interface
  7. uses Dos, Crt;
  8.  
  9. const
  10.   Baud300     = $40;  Baud1200    = $80;  Baud2400    = $A0;
  11.   Baud4800    = $C0;  Baud9600    = $E0;
  12.   EvenParity  = $18;  OddParity   = $08;  NoParity    = $00;
  13.   WordSize7   = $02;  WordSize8   = $03;
  14.   StopBits1   = $04;  StopBits2   = $00;
  15.   COM1Port    = $00;  COM2Port    = $01;
  16.  
  17. procedure ComInit(BufSize: Word);
  18. procedure ComDone;
  19. function ComAvail: Boolean;
  20. function ComGet: Byte;
  21. function ComOverflow: Boolean;
  22. procedure ComPut(B: Byte);
  23. procedure ComPutString(S: String);
  24. function ComSetParam(APortNum, AParams: Word): Boolean;
  25.  
  26. Implementation
  27. uses Objects;
  28.  
  29. const
  30.   UART_THR  = $00;  UART_RBR  = $00;  UART_IER  = $01;
  31.   UART_IIR  = $02;  UART_LCR  = $03;  UART_MCR  = $04;
  32.   UART_LSR  = $05;  UART_MSR  = $06;  I8088_IMR = $21;
  33.   FirstInit: Boolean = True;
  34.  
  35. var
  36.   Overflow: Boolean;
  37.   PortNum, Base, Max, Head, Tail: Word;
  38.   BufferPtr: PByteArray;
  39.   SaveCom1Int, SaveCom2Int: Pointer;
  40.   IRQ, IntNumber: Byte;
  41.  
  42. procedure STI; inline($FB);
  43. procedure CLI; inline($FA);
  44.  
  45. procedure ComIntHandler; interrupt; assembler;
  46. asm
  47.   STI
  48.   MOV   DX,Base          { Receive buffer register is at offset 0 }
  49.   IN    AL,DX
  50.   LES   DI,BufferPtr     { get pointer into the buffer }
  51.   MOV   BX,Head
  52.   MOV   ES:[DI+BX],AL    { put character into buffer }
  53.   INC   BX               { increment }
  54.   CMP   BX,Max           { do we need a wrap around ? }
  55.   JL    @@1
  56.   MOV   BX,0
  57. @@1:
  58.   CMP   Tail,BX          { buffer overflow ? }
  59.   JNE   @@2
  60.   INC   Overflow
  61.   JMP   @@3
  62. @@2:
  63.   MOV   Head,BX          { put head pointer back }
  64. @@3:
  65.   MOV   AL,$20
  66.   OUT   $20,AL           { send non-specific EOI to interrupt controller }
  67. end;
  68.  
  69. procedure BiosInitCom(APortNum, AParams: Word); assembler;
  70. asm
  71.   MOV   AX,AParams
  72.   MOV   DX,APortNum
  73.   XOR   AH,AH
  74.   INT   14H
  75. end;
  76.  
  77. procedure ComInit(BufSize: Word);
  78. begin
  79.   if not FirstInit then RunError(255);
  80.   FirstInit:=False;
  81.   GetIntVec($C, SaveCom1Int);
  82.   GetIntVec($B, SaveCom2Int);
  83.   GetMem(BufferPtr, BufSize);
  84.   Max:=BufSize;
  85. end;
  86.  
  87. procedure ComDone;
  88. begin
  89.   if not FirstInit then
  90.   begin
  91.     SetIntVec($C, SaveCom1Int);
  92.     SetIntVec($B, SaveCom2Int);
  93.     FreeMem(BufferPtr, Max);
  94.     CLI;
  95.       Port[I8088_IMR] := Port[I8088_IMR] or (1 shl IRQ);
  96.       Port[UART_IER + Base] := 0;
  97.       Port[UART_MCR + Base] := 0;
  98.     STI;
  99.   end;
  100.   FirstInit := True;
  101. end;
  102.  
  103. function ComAvail: Boolean;
  104. begin
  105.   ComAvail:= Head <> Tail;
  106. end;
  107.  
  108. function ComGet: Byte;
  109. begin
  110.   repeat until Head <> Tail;
  111.   ComGet := BufferPtr^[Tail];
  112.   CLI;
  113.     Inc(Tail);
  114.     if Tail >= Max then Tail := 0;
  115.   STI;
  116. end;
  117.  
  118. function ComOverflow: Boolean;
  119. begin
  120.   ComOverflow:=Overflow;
  121. end;
  122.  
  123. procedure ComPut(B: Byte);
  124. begin
  125.   while (Port[UART_LSR + Base] and $20) = 0 do;
  126.   CLI;
  127.     Port[UART_THR + Base] := B;
  128.   STI;
  129. end;
  130.  
  131. procedure ComPutString(S: String);
  132. var L: Integer;
  133. begin
  134.   for L := 1 to Length(S) do ComPut(Ord(S[L]));
  135. end;
  136.  
  137. function ComSetParam(APortNum, AParams: Word): Boolean;
  138. var
  139.   BIOSPorts : array[1..2] of Word absolute $40:0;
  140.   Junk: Word;
  141. begin
  142.   SetIntVec($C, SaveCom1Int);
  143.   SetIntVec($B, SaveCom2Int);
  144.   Overflow := False;
  145.   Head := 0;
  146.   Tail := 0;
  147.   Base := BIOSPorts[APortNum + 1];
  148.   IRQ := Hi(Base) + 1;
  149.   IntNumber := IRQ + $8;
  150.   if (Port[UART_IIR + Base] and $F8) = 0 then
  151.   begin
  152.     SetIntVec(IntNumber, @ComIntHandler); { install interrupt handler }
  153.     PortNum := APortNum;
  154.     BiosInitCom(APortNum, AParams); { use BIOS call for easy param setting }
  155.     CLI;
  156.       Port[UART_LCR + Base] := Port[UART_LCR + Base] and $7F;
  157.       Port[I8088_IMR] := Port[I8088_IMR] and ((1 shl IRQ) xor $FF);
  158.                                         { enable PIC to recognize IRQ's }
  159.       Port[UART_IER + Base] := $01; { allow UART to generate IRQ's }
  160.       Port[UART_MCR + Base] := Port[UART_MCR + Base] or $0B;
  161.       Junk := Port[UART_LSR + Base];  { clear these registers }
  162.       Junk := Port[UART_RBR + Base];
  163.     STI;
  164.     ComSetParam:=True
  165.   end
  166.   else ComSetParam := False;
  167. end;
  168. end.
  169.